#include <video.h>
#include <kernel/gdt.h>
#include <kernel/syscall.h>
#include <kernel/system.h>
#include <kernel/sched.h>
#include <kernel/puertos.h>
#include <kernel/semaforo.h>
#include <shell/teclado.h>
#include <shell/shell.h>
#include <kernel/shm.h>
#include <fs/ramfs.h>
#include <kernel/mem/mem_part_firstfit.h>
#include <kernel/mem/mem_part_kernel.h>
#include <kernel/mem/paginas.h>

#include <kernel/definiciones.h>
extern stuPCB pstuPCB[CANTMAXPROCS];
extern stuTSS stuTSSTablaTareas[CANTMAXPROCS];
extern unsigned long ulProcActual;
extern unsigned long ulUltimoProcesoEnFPU;
extern short int bPlanificador;

extern unsigned long uliQuantum;
extern unsigned long uliBTSQ;

extern unsigned int uiModoMemoria;

// Ver declaraci?n en system.c
extern unsigned long ulTiempo;
// Ver declaraci?n en system.c
extern int iMinuteswest;
// Ver declaraci?n en system.c
extern unsigned int iMilisegundosPorTick;
// Ver declaraci?n en system.c
extern long lRelojOffset;
// Ver declaraci?n en system.c
extern long lRelojFrequencia;
// Ver declaraci?n en system.c
extern long lRelojMaxerror;
// Ver declaraci?n en system.c
extern long lRelojEsterror;
// Ver declaraci?n en system.c
extern long lRelojConstante;
// Ver declaraci?n en system.c
extern int iRelojEstado;

extern void vFnIniciarTimer_Asm(int divisor);

/* macro que toma el DS del proceso usuario, y lo usa temporalmente
 * para guardar un valor 'val' en el offset dado dentro de ese segmento
 * (se usa cuando un syscall recibe un puntero a un dato, que no es mas
 * que un offset dentro del segmento de datos correspondiente).
 * esto se podria haber hecho tambien tomando la direccion base almacenada
 * en la PCB del invocador, pero era muy facil ;) */
#define	_copiar_a_userland( ds, offset, val ) 	\
	__asm__ volatile (			\
		 "pushl	%%ds		\n\t"	\
		 "movl	%0, %%ds	\n\t"	\
		 "movl	%2, (%1)	\n\t"	\
		 "popl	%%ds		\n\t"	\
		 :: "a"( ds ),			\
		    "b"( offset ),		\
		    "c"( val ) )


/******************************************************************************
Funcion:
Descripcion:
Recibe:
Devuelve:
*******************************************************************************/
long lFnSysExit(int status)
{
	int iPCBPadre =
	    iFnBuscaPosicionProc(pstuPCB[ulProcActual].ulParentId);

	/*vFnImprimir( "\n exit(): el proceso %d esta terminando con estado %d",
	   pstuPCB[ ulProcActual ].ulId,
	   status ); */
	pstuPCB[ulProcActual].iEstado = PROC_ZOMBIE;
	pstuPCB[ulProcActual].iExitStatus = status;

	/*vFnImprimir( "\n exit(): mi padre %d %s (%d)",
	   pstuPCB[ ulProcActual ].ulParentId,
	   pstuPCB[ iPCBPadre ].iEstado == PROC_ESPERANDO ? "ME esta esperando" : "me abandono",
	   pstuPCB[ iPCBPadre ].iEstado ); */
	if (pstuPCB[iPCBPadre].iEstado == PROC_ESPERANDO) {
		/*vFnImprimir( "\n exit(): el proceso %d despierta a su padre %d",
		   pstuPCB[ ulProcActual ].ulId,
		   pstuPCB[ iPCBPadre ].ulId ); */
		pstuPCB[iPCBPadre].iEstado = PROC_LISTO;
	}

	// llamar al planificador, para que este proceso no se ejecute nunca mas,
	// ya que queda en estado ZOMBIE
	vFnPlanificador();

	return 0;
}
/******************************************************************************
Funcion:
Descripcion:
Recibe:
Devuelve:
*******************************************************************************/
long lFnSysFork()
{

	int ret = iFnDuplicarProceso(ulProcActual);

	//vFnLog("\nlFnSysFork(): iFnDuplicarProceso retorna: %d",ret);
	if (ret < 0)
          {
                if (pstuPCB[iFnBuscaPosicionProc(ulProcActual)].stuEsperaMemoria.iEstado != FORK)  vFnImprimir("\nSuspendido %d a la espera de que se liberen %d Bytes tras intentar FORK...",ulProcActual,liTamanioSolicitado);
		pstuPCB[iFnBuscaPosicionProc(ulProcActual)].stuEsperaMemoria.iEstado = FORK;
		pstuPCB[iFnBuscaPosicionProc(ulProcActual)].stuEsperaMemoria.liTamanio = liTamanioSolicitado;
		pstuPCB[iFnBuscaPosicionProc(ulProcActual)].iEstado = PROC_ESPERANDO;
                return 1;
          }
	//XXX Para debuguear el estado del nuevo proceso lanzado (tss, stack, y pcb) podemos detenerlo antes de que tenga la oportunidad de ser ejecutado
	// pstuPCB[ret].iEstado=PROC_DETENIDO;

	return pstuPCB[ret].ulId;	// al padre le retornamos el PID del hijo
}
/******************************************************************************
Funcion:
Descripcion:
Recibe:
Devuelve:
*******************************************************************************/
long lFnSysTest(long num)
{
	  vFnImprimir("%d", num);
	return 0;
}

/******************************************************************************
Funcion:
Descripcion:
Recibe:
Devuelve:
*******************************************************************************/
long lFnSysRead(int fd, void *buf, size_t count)
{
	unsigned int uiBase;
	unsigned char *pstPuntero;

        int cCaracter;


    // La espera activa se hace desde el proceso usuario. Esto es solo un If,
    // si hay algo nuevo lo trae, sino retorna -1
    //vFnImprimir("\ngetchar: Antes de espera activa");
    if (staiVaciarIndice == iLlenarIndice)
       {
        pstuPCB[iFnBuscaPosicionProc(ulProcActual)].uiEsperaTeclado = 1;
        pstuPCB[iFnBuscaPosicionProc(ulProcActual)].iEstado = PROC_ESPERANDO;
        return -1;
       }


    //vFnImprimir("\ngetchar: Luego de espera activa. staiVaciarIndice=%d, iLlenarIndice=%d",staiVaciarIndice, iLlenarIndice);
    while (iSemaforoBufferTeclado != 0);
    iSemaforoBufferTeclado = 1;

    cCaracter = stBufferTeclado[staiVaciarIndice++];

    //vFnImprimir("\ngetchar: cCaracter: %c, staiVaciarIndice=%d, iLlenarIndice=%d",cCaracter, staiVaciarIndice, iLlenarIndice);

    if (staiVaciarIndice > (TAMANIO_BUFFER_TECLADO - 1))
    {
        staiVaciarIndice = 0;
       // vFnImprimir("\ngetchar: Llegamos al final del buffer.   staiVaciarIndice=%d, iLlenarIndice=%d", staiVaciarIndice, iLlenarIndice);
    }

    //vFnImprimir("\ngetchar: Fin, retornamos Caracter: %c",cCaracter);
    iSemaforoBufferTeclado = 0;

	/* Si fd = 0, nos guiamos por el PID actual, si source = 1, nos fijamos
           en el code segment llamador */
        /* ignoramos por el momento el descriptor fd y el parametro 'count' */
        if (!fd)
          {
          pstPuntero = (unsigned char *) (pstuPCB[ulProcActual].uiDirBase + (unsigned int) buf);
          *pstPuntero = cCaracter;
          }
	else
          {
            uiBase = pstuTablaGdt->stuGdtDescriptorDescs[fd].usBaseBajo;
	    uiBase += pstuTablaGdt->stuGdtDescriptorDescs[fd].ucBaseMedio * 0x10000;
	    uiBase += pstuTablaGdt->stuGdtDescriptorDescs[fd].usBaseAlto * 0x1000000;
            pstPuntero = (unsigned char *) (uiBase + (unsigned int) buf);
            *pstPuntero = cCaracter;
          }

         if((unsigned int)cCaracter == -6) cCaracter = TECLA_ARR;
         if((unsigned int)cCaracter == -5) cCaracter = TECLA_IZQ;
         if((unsigned int)cCaracter == -4) cCaracter = TECLA_DER;
         if((unsigned int)cCaracter == -3) cCaracter = TECLA_ABA;

	return cCaracter;		/*devuelve Numero de tecla ingresada */
}
/******************************************************************************
Funcion:
Descripcion:
Recibe:
Devuelve:
*******************************************************************************/
long lFnSysWrite(int iVentana, const void *buf, size_t count)
{
        if(iFnCompararCadenas(pstuPCB[ulProcActual].stNombre,"SHELLUSR.BIN") == 1 || iVentana == 0) vFnImprimir("%s", (unsigned char *) (pstuPCB[ulProcActual].uiDirBase + (unsigned int) buf));
        else vFnImprimirVentana (HWND_PROCESOS, "%s", (unsigned char *) (pstuPCB[ulProcActual].uiDirBase + (unsigned int) buf));
	return 0;		/* supuestamente devuelve la cantidad de bytes escritos */


}


/******************************************************************************
Funcion:
Descripcion:
Recibe:
Devuelve:
*******************************************************************************/
long lFnSysWaitPid(int pid, int *status, int options)
{
	int iPCBHijo = iFnBuscaPosicionProc(pid);

	/* si no encontramos el proceso por PID, devolvemos ECHILD, para
	 * ser compatibles con POSIX */
	if (iPCBHijo < 0) {
		return -ECHILD;
	}

	/*vFnImprimir( "\n waitpid(): mi hijo %d %s",
	   pid, pstuPCB[ iPCBHijo ].iEstado != PROC_ZOMBIE ? "NO esta zombie" : "Ya esta zombie" ); */
	while (pstuPCB[iPCBHijo].iEstado != PROC_ZOMBIE) {
		/*vFnImprimir( "\n waitpid(): esperando que %d termine", pid ); */
		pstuPCB[ulProcActual].iEstado = PROC_ESPERANDO;
		/* llamamos al planificador para que nos quite y pueda
		 * ejecutar el hijo, de forma tal que en algun momento
		 * termine, y se pueda volver */
		vFnPlanificador();
		/*vFnImprimir( "\n waitpid(): %d me desperto", pid ); */
	}

	/* si estamos aca, significa que el hijo ya esta zombie, o bien
	 * porque ya lo estaba ni bien arranco la syscall, o porque lo esperamos
	 * cambiando nuestro estado a PROC_ESPERANDO (despues de varias esperas
	 * posiblemente) */

	/* ahora que termino, recolectamos su estado, copiandolo
	 * al proceso padre en 'status' */

	/*_copiar_a_userland( stuTSSTablaTareas[ ulProcActual ].ds,
			    status,
			    pstuPCB[ iPCBHijo ].iExitStatus );*/

	*(int *) (pstuPCB[ulProcActual].uiDirBase +
		  (unsigned char *) status) =
	    pstuPCB[iPCBHijo].iExitStatus;

	/* ahora si lo marcamos como eliminado, y liberamos todo lo que estaba utilizando */
	iFnEliminarProceso(iPCBHijo);

	return pid;
}


/******************************************************************************
Funcion: long lFnSysExecve(const char *filename, char *argv[],  char *const envp[])
Descripcion: Permite a un proceso reemplazarse a si mismo por un archivo binario
Recibe:
Devuelve:
*******************************************************************************/
long lFnSysExecve(const char *filename, char *argv[],  char *envp[])
{
    int iReturnCode;
	int i,j,k;
	int iArgvSize, iEnvpSize;
	int iArgc, iEnvArgc;

	int *piVectorEnviroment;
	int *piVectorArgv;

	unsigned int uiOffset;
	unsigned int uiOffsetTemp;

	stEntradaLS *pstEntLs;
	stDirectorio *pstDirBusqueda;

	char* strNombreArchivo =(char*)((unsigned int)pstuPCB[ulProcActual].uiDirBase + (unsigned int)filename);
    char* stArgvTemp, *stEnvpTemp;

    char** pstArgvPointers, **pstEnvpPointers;


	if (iFnObtenerDirectorio("/mnt/usr", &pstDirBusqueda) < 0) {
		vFnImprimir
		    ("\nSodium Dice: Error! El directorio no existe");
		return -ENOENT;
	}

	if (iFnBuscarArchivo(pstDirBusqueda, strNombreArchivo, &pstEntLs) < 0) {
		vFnImprimir
		    ("\nSodium Dice: Error! Archivo no encontrado (%s)",
		     strNombreArchivo);
		return -ENOENT;
	}


	/////////////////  Comienzo de seteo de enviroment, y argc / argv.///////////////////////////
    //  Antes de setear la posicion de ESP / EBP, debemos calcular el offset de comienzo  ///////
    //  de EBP y ESP respecto al final del segmento de datos           //////////////////////////
    //  donde se guardaran argc, argv y el enviroment.                 //////////////////////////
    //  Sergio Martin - 2010                                           //////////////////////////
    /////////////////////////////////////////////////////////////////////////////////////////////
    uiOffset = 0;

	// Determinando tamaño del Enviroment
		 envp = (int)envp + pstuPCB[ulProcActual].uiDirBase; // Le sumo la base del proceso al offset del envp recibido
		 iEnvArgc = 0;
		 // Voy a obtener la cantidad de Argumentos ademas de sumarle a cada uno la direccion base del proceso
		 while(envp[iEnvArgc] != 0	) {
		 envp[iEnvArgc] = (int)envp[iEnvArgc] + pstuPCB[ulProcActual].uiDirBase; iEnvArgc++;
		 }

		iEnvpSize = 0;
		for(i=0; i < iEnvArgc; i++)
		  {
			j = 0;
			while(envp[i][j] != '\0') j++;
			iEnvpSize = iEnvpSize + j +1 ;
		  }


		// Reservo la memoria para hacer copias temporales del enviroment en el kernel
		stEnvpTemp = (char*)pvFnReservarParticionUsuario(iEnvpSize * sizeof(char));
		pstEnvpPointers = (char**)pvFnReservarParticionUsuario(iEnvArgc * sizeof(char*));

		// Efectuo las copias del espacio de usuario a la nueva posicion en kernel
		// Porque iFnReemplazarProceso va a pisar toda esa información
		// y a envp lo paso en una sola cadena continua en stEnvpTemp
		k = 0;
		for(i=0; i < iEnvArgc; i++)
		  {
			j = 0;
			while(envp[i][j] != '\0')
			  {
				stEnvpTemp[k] = envp[i][j];
				j++;
				k++;
			  }
			stEnvpTemp[k] = '\0';
			k++;
		  }

		stEnvpTemp[iEnvpSize-1] = '\0';

		// Seteo la nueva posicion relativa de las cadenas respecto a los punteros
		j = 0;
		for(i = 0; i < iEnvpSize; i++)
		  {
			if(i == 0) { pstEnvpPointers[0] = 0; j++; }
			else if (stEnvpTemp[i-1] == '\n') { pstEnvpPointers[j] = i; j++;}
		  }



	// Determinando tamaño de ARGV Y ARGC

		argv = (int)argv + pstuPCB[ulProcActual].uiDirBase; // Le sumo la base del proceso al offset del argv recibido
		iArgc=0;
		// Voy a obtener la cantidad de Argumentos ademas de sumarle a cada uno la direccion base del proceso
		while(argv[iArgc] != 0	) {
			 argv[iArgc] = (int)argv[iArgc] + pstuPCB[ulProcActual].uiDirBase; iArgc++;
			 }

		// Ahora obtengo el tamaño total en bytes que ocupa el argv crudo
		iArgvSize = 0;
		for(i=0; i < iArgc; i++)
		  {
			j = 0;
			while(argv[i][j] != '\0') j++;
			iArgvSize = iArgvSize + j +1 ;
		  }

		// Reservo la memoria para hacer copias temporales de los argumentos en el kernel
		stArgvTemp = (char*)pvFnReservarParticionUsuario(iArgvSize * sizeof(char));
		pstArgvPointers = (char**)pvFnReservarParticionUsuario(iArgc * sizeof(char*));

		// Efectuo las copias del espacio de usuario a la nueva posicion en kernel
		// Porque iFnReemplazarProceso va a pisar toda esa información
		// y a Argv lo paso en una sola cadena continua en stArgvTemp
		k = 0;
		for(i=0; i < iArgc; i++)
		  {
			j = 0;
			while(argv[i][j] != '\0')
			  {
				stArgvTemp[k] = argv[i][j];
				j++;
				k++;
			  }
			stArgvTemp[k] = '\0';
			k++;
		  }

		// Seteo la nueva posicion relativa de las cadenas respecto a los punteros
		j = 0;
		for(i = 0; i < iArgvSize; i++)
		  {
			if(i == 0) { pstArgvPointers[0] = 0; j++; }
			else if (stArgvTemp[i-1] == '\0') { pstArgvPointers[j] = i; j++;}
		  }


		// En este punto calculo el offset que debe tener
		uiOffset = uiOffset + sizeof(int); // argc
		uiOffset = uiOffset + sizeof(char*); // Vector al primer elemento del enviroment
		uiOffset = uiOffset + sizeof(char*); // Vector al primer elemento de Argv
		uiOffset = uiOffset + sizeof(char**); // argv
		uiOffset = uiOffset + sizeof(char**); // envp
		uiOffset = uiOffset + iEnvpSize; // Tamaño de la cadena de enviroment
		uiOffset = uiOffset + iArgvSize; // Tamaño de las cadenas de parametros combinadas
		uiOffset = uiOffset + (iArgc+1) * sizeof(int) ; // Tamaño de los punteros del argumento mas el nulo final
		uiOffset = uiOffset + (iEnvArgc+1) * sizeof(int) ; // Tamaño de los punteros del enviroment mas el nulo final
		uiOffset = uiOffset + sizeof(int) ; // Para posicionar en el primer lugar de lectura a argc


		// Ejecutamos iFnReemplazarProceso.
		// Esto va a reemplazar cualquier dato que hayamos usado, por lo que debimos crear backups temporales de todos los datos
		// Ademas si no encuentra memoria para hacer el transpaso, el proceso se encola en una lista de espera
        iReturnCode = iFnReemplazarProceso( pstuPCB[ulProcActual].ulId, strNombreArchivo,  uiOffset);

		// Si no hubo memoria, pongo el proceso en cola de espera
		if (iReturnCode < 0)
			  {
				   if (pstuPCB[iFnBuscaPosicionProc(pstuPCB[ulProcActual].ulId)].stuEsperaMemoria.iEstado != EXEC) vFnImprimir("\nSuspendido %d a la espera de que se liberen %d Bytes tras intentar EXEC...",ulProcActual,liTamanioSolicitado);
					pstuPCB[iFnBuscaPosicionProc(pstuPCB[ulProcActual].ulId)].stuEsperaMemoria.iEstado = EXEC;
					pstuPCB[iFnBuscaPosicionProc(pstuPCB[ulProcActual].ulId)].stuEsperaMemoria.liTamanio = liTamanioSolicitado;
					pstuPCB[iFnBuscaPosicionProc(pstuPCB[ulProcActual].ulId)].iEstado = PROC_ESPERANDO;
							return 1;
			 }


		// Ahora vamos a usar uiOffset para otro proposito. Va a ir incrementandose a medida que volcamos la informacion
		// En el stack, sirviendo como un puntero dinamico de la posicion actual, haciendo mucho mas facil establecer
		// Los punteros entre datos del stack. Al final de todo va a terminar con el mismo valor que calculamos antes.
		uiOffset = 0;
		// Comenzamos la copia del Enviroment
		ucpFnCopiarMemoria((unsigned char*)pstuPCB[iFnBuscaPosicionProc(pstuPCB[ulProcActual].ulId)].uiDirBase + POS_STACK - iEnvpSize ,(unsigned char*)stEnvpTemp, iEnvpSize);
		uiOffset = uiOffset + iEnvpSize;

		// Creamos los punteros del enviroment
	    // Seteamos los punteros a cada palabra de adelante hacia atras
        // Primero el último puntero nulo
	    uiOffset = uiOffset + sizeof(int);



		  for( i = iEnvpSize -1 ; i > 0; i--) // el -1 es porque no queremos tener en cuenta el '\0' final ppd.
			{
			   if(stEnvpTemp[i] == '\0')
				 {
					uiOffset = uiOffset + sizeof(int);
					*(int*)(pstuPCB[iFnBuscaPosicionProc(pstuPCB[ulProcActual].ulId)].uiDirBase + POS_STACK - uiOffset ) = POS_STACK  - iEnvpSize + i +1 ; // El +1 es porque queremos el Inicio de la cadena, No el '\0'
				 }
			}

		uiOffset = uiOffset + sizeof(int);
	    piVectorEnviroment = POS_STACK - uiOffset;
		*(int*)(pstuPCB[iFnBuscaPosicionProc(pstuPCB[ulProcActual].ulId)].uiDirBase + POS_STACK - uiOffset) = POS_STACK - iEnvpSize;


	    // Comenzamos la copia de Argv
		uiOffsetTemp = uiOffset; // uiOffsetTemp es la marca de fin de enviroment para comienzo de copia de Argv
		ucpFnCopiarMemoria((unsigned char*)pstuPCB[iFnBuscaPosicionProc(pstuPCB[ulProcActual].ulId)].uiDirBase + POS_STACK - uiOffsetTemp - iArgvSize ,(unsigned char*)stArgvTemp, iArgvSize);
		uiOffset = uiOffset + iArgvSize;

		// Creamos los punteros de argv
	    // Seteamos los punteros a cada palabra de adelante hacia atras
        // Primero el último puntero nulo
	    uiOffset = uiOffset + sizeof(int);
		*(int*)(pstuPCB[iFnBuscaPosicionProc(pstuPCB[ulProcActual].ulId)].uiDirBase + POS_STACK - uiOffset ) = 0 ;


		  for( i = iArgvSize -1 ; i > 0; i--) // el -1 es porque no queremos tener en cuenta el '\0' final ppd.
			{
			   if(stArgvTemp[i] == '\0')
				 {
					uiOffset = uiOffset + sizeof(int);
					*(int*)(pstuPCB[iFnBuscaPosicionProc(pstuPCB[ulProcActual].ulId)].uiDirBase + POS_STACK - uiOffset ) = POS_STACK  - uiOffsetTemp - iArgvSize + i +1 ; // El +1 es porque queremos el Inicio de la cadena, No el '\0'
				 }
			}

		uiOffset = uiOffset + sizeof(int);
	    piVectorArgv = POS_STACK - uiOffset;
		*(int*)(pstuPCB[iFnBuscaPosicionProc(pstuPCB[ulProcActual].ulId)].uiDirBase + POS_STACK - uiOffset) = POS_STACK - uiOffsetTemp - iArgvSize;

		// Creamos el puntero doble envp
		uiOffset = uiOffset + sizeof(char**); // envp
		*(int*)(pstuPCB[iFnBuscaPosicionProc(pstuPCB[ulProcActual].ulId)].uiDirBase + POS_STACK - uiOffset) = piVectorEnviroment;

		// Creamos el puntero doble argv
		uiOffset = uiOffset + sizeof(char**); // argv
		*(int*)(pstuPCB[iFnBuscaPosicionProc(pstuPCB[ulProcActual].ulId)].uiDirBase + POS_STACK - uiOffset) = piVectorArgv;

		// Creamos argc
		uiOffset = uiOffset + sizeof(int); // argc
		*(int*)(pstuPCB[iFnBuscaPosicionProc(pstuPCB[ulProcActual].ulId)].uiDirBase + POS_STACK - uiOffset) = iArgc; // int argc*/

		*(int*)(pstuPCB[iFnBuscaPosicionProc(pstuPCB[ulProcActual].ulId)].uiDirBase + POS_STACK - iEnvpSize - 2*sizeof(int)) = 0 ; // Clausuramos el vector de punteros del enviroment

		// Liberamos todos los recursos de memoria utilizados
		vFnKFree(stEnvpTemp);
		vFnKFree(pstEnvpPointers);
		vFnKFree(stArgvTemp);
		vFnKFree(pstArgvPointers);

		// Renombramos el proceso a su nuevo nombre
		iFnCopiaCadena(pstuPCB[iFnBuscaPosicionProc(pstuPCB[ulProcActual].ulId)].stNombre, strNombreArchivo);
	return iReturnCode;
}
/******************************************************************************
Funcion:
Descripcion:
Recibe:
Devuelve:
*******************************************************************************/
long lFnSysTime(long *lT)
{
	long lTime = 17;

	/* XXX buscar un valor para devolver realmente */
	vFnImprimir
	    ("\n time(): el proceso actual %d usa DS=%x guardamos %d en %x",
	     ulProcActual, stuTSSTablaTareas[ulProcActual].ds, lTime, lT);

	_copiar_a_userland(stuTSSTablaTareas[ulProcActual].ds, lT, lTime);

	return lTime;
}
/******************************************************************************
Funcion:
Descripcion:
Recibe:
Devuelve:
*******************************************************************************/
long lFnSysGetPid()
{

	return pstuPCB[ulProcActual].ulId;
}


/**
 * \brief Envia una senal a un proceso
 * \param pid Pid del proceso
 * \param sig Numero de senal
 * \returns 0 si se completo con exito, < 0 si ocurrio un error
 */
long lFnSysKill(int pid, int sig)
{
	int iPosicionPCB = iFnBuscaPosicionProc(pid), iPCBPadre = 0;

	/* si no encontramos el proceso por PID, devolvemos ESRCH
	 * (requerido por POSIX) */
	if (iPosicionPCB < 0
	    || pstuPCB[iPosicionPCB].iEstado == PROC_ZOMBIE) {
		return -ESRCH;
	}

	switch (sig) {
    case (SIGFPE):
        //TODO - Realizar tratamiento de la senial
        vFnImprimir(
            "\nSe recibio SIGFPE (Error en operacion de punto flotante)");
        goto eliminarproceso; //TODO - Cambiar por un tratamiento man apropiado
	case (SIGSEGV):
        vFnImprimir("\nSe recibio SIGSEGV en el Proceso PID=%d \"%s\" ",
                pstuPCB[iPosicionPCB].ulId, pstuPCB[iPosicionPCB].stNombre);
        goto eliminarproceso; //TODO - Cambiar por un tratamiento man apropiado
	case (SIGINT):
	case (SIGTERM):
	case (SIGKILL):
eliminarproceso:
		/* buscamos al padre para despertarlo, de ser necesario */
		iPCBPadre =
		    iFnBuscaPosicionProc(pstuPCB[iPosicionPCB].ulParentId);
		/* forzamos la salida del proceso, dejandolo en estado zombie, y
		 * almacenando -1 como valor de salida (valor arbitrario, deberian
		 * implementarse las macros que separan valores de salida del estado
		 * de salida forzado por señal) */
		pstuPCB[iPosicionPCB].iEstado = PROC_ZOMBIE;
		pstuPCB[iPosicionPCB].iExitStatus = -1;
		/* despertamos al padre, si estaba esperando */
		if (pstuPCB[iPCBPadre].iEstado == PROC_ESPERANDO) {
			pstuPCB[iPCBPadre].iEstado = PROC_LISTO;
		}
		break;
	case (SIGSTOP):
		if (pstuPCB[iPosicionPCB].iEstado == PROC_LISTO ||
		    pstuPCB[iPosicionPCB].iEstado == PROC_EJECUTANDO) {
			vFnImprimir
			    ("\n pasando el proceso %d (en estado %d) a estado DETENIDO ",
			     pid, pstuPCB[iPosicionPCB].iEstado);
			pstuPCB[iPosicionPCB].iEstado = PROC_DETENIDO;
		}
		break;
	case (SIGCONT):
		if (pstuPCB[iPosicionPCB].iEstado == PROC_DETENIDO)
			pstuPCB[iPosicionPCB].iEstado = PROC_LISTO;
		break;
	default:
		return -EINVAL;
	}

	return 0;
}


/******************************************************************************
Funcion:
Descripcion:
Recibe:
Devuelve:
*******************************************************************************/
long lFnSysGetPPid()
{
	return pstuPCB[ulProcActual].ulParentId;
}
/******************************************************************************
Funcion:
Descripcion:
Recibe:
Devuelve:
*******************************************************************************/
long lFnSysReboot(int flag)
{
	outb(0xfe, 0x64);
	return -ENOSYS;
}

// ****************     TP 3 - 2007 - Syscalls de IPC    *****************

/**
 * @brief (Sergio Martin, 2009) Syscall. Le otorga a los procesos usuario una lista de funcionalidades que solo pueden ser ejecutadas en kernel.
 * @param iOpcion. Numero de opcion. La lista puede ser vista en syscall.h
 * @param iPar1. Primer parametro para la funcion
 * @param iPar2. Segundo parametro para la funcion
 * @date 20/11/2009
 */
long lFnSysSodiumCallgate(int iOpcion, int iPar1, int iPar2)
{
        if(iOpcion == __FC_LOG)      vFnCambiarTerminal();
        if(iOpcion == __FC_COLOR)    vFnSysSetearColor(iPar1, iPar2);
        if(iOpcion == __FC_CLS)      vFnMenuCls();
        if(iOpcion == __FC_GDT)      vFnMenuGdt(iPar1);
        if(iOpcion == __FC_VERSEM)   vFnMenuVerSemaforos();
        if(iOpcion == __FC_VERSHM)   vFnMenuVerShm();
        if(iOpcion == __FC_GETPID)   vFnImprimir("\nel syscall getpid() me devolvio %d", lFnSysGetPid());
        if(iOpcion == __FC_GETPPID)  vFnImprimir("\nel syscall getppid() me devolvio %d", lFnSysGetPPid());
        if(iOpcion == __FC_REBOOT)   lFnSysReboot(0);
        if(iOpcion == __FC_PS)       vFnMenuPs();
        if(iOpcion == __FC_MEM)      vFnMenuMem();
        if(iOpcion == __FC_SEGS)     vFnMenuSegs();
	if(iOpcion == __FC_BITMAP)   vFnImprimirMapaBits();
	if(iOpcion == __FC_IDT)	     vFnMenuIdt(iPar1);
	if(iOpcion == __FC_YIELD)    lFnSysSchedYield();
	if(iOpcion == __FC_PAG)	     vFnMenuPag(iPar1);
	if(iOpcion == __FC_TSS)	     vFnMenuTSS(iPar1);
	if(iOpcion == __FC_STACK)    vFnMenuStack(iPar1,iPar2);
	if(iOpcion == __FC_EXEC)     vFnMenuExec(iPar1,iPar2);
	if(iOpcion == __FC_PLANIF)   if(iPar2==5) vFnMenuPlanif(pstuPCB[iFnBuscaPosicionProc(ulProcActual)].uiDirBase+iPar1,iPar2);
				     else vFnMenuPlanif(iPar1,iPar2);
	//Inicio modificacion Fernando***********
	//***************************************
	if(iOpcion == __FC_LEER)     vFnMenuLeerArch(pstuPCB[iFnBuscaPosicionProc(ulProcActual)].uiDirBase+iPar1);
	if(iOpcion == __FC_DUMP)     vFnMenuDump(iPar1,iPar2);
	if(iOpcion == __FC_CD)       vFnMenuCD(pstuPCB[iFnBuscaPosicionProc(ulProcActual)].uiDirBase+iPar1);
	if(iOpcion == __FC_LS)       vFnMenuLs(pstuPCB[iFnBuscaPosicionProc(ulProcActual)].uiDirBase+iPar1);
	if(iOpcion == __FC_RM)       vFnMenuRm(pstuPCB[iFnBuscaPosicionProc(ulProcActual)].uiDirBase+iPar1);
	if(iOpcion == __FC_WRITE)    vFnMenuWriteArch(pstuPCB[iFnBuscaPosicionProc(ulProcActual)].uiDirBase+iPar1,pstuPCB[iFnBuscaPosicionProc(ulProcActual)].uiDirBase+iPar2);
	if(iOpcion == __FC_KILL)     vFnMenuOptKill(iPar1);
	if(iOpcion == __FC_SYSK)     return lFnSysKill(iPar1, iPar2);
	//Fin modificacion Fernando**************
	//***************************************

	if(iOpcion == __FC_CHECK)    {if (uiModoMemoria == MODOPAGINADO) vFnMenuCheck(iPar1);	//CORREGIR!!! agregar hasta 3er param
                                     else  vFnImprimir("\nError: Comando no aplicable.");}
        if(iOpcion == __FC_WAITPID)  vFnEsperarPID(iPar1);
        if(iOpcion == __FC_LOTE)     {int *iP;
                                     iP=pstuPCB[iFnBuscaPosicionProc(ulProcActual)].uiDirBase+iPar2;
                                     vFnMenuLotes(pstuPCB[iFnBuscaPosicionProc(ulProcActual)].uiDirBase+iPar1, pstuPCB[iFnBuscaPosicionProc(ulProcActual)].uiDirBase+iP[0], pstuPCB[iFnBuscaPosicionProc(ulProcActual)].uiDirBase+iP[1]);
                                     }
        if(iOpcion == __FC_PCB)      vFnMenuPCB(iPar1);
        if(iOpcion == __FC_DESC)     vFnMenuDesc(pstuPCB[iFnBuscaPosicionProc(ulProcActual)].uiDirBase+iPar1,iPar2);
        if(iOpcion == __FC_EJECUTAR) vFnMenuEjecutar(pstuPCB[iFnBuscaPosicionProc(ulProcActual)].uiDirBase+iPar1);
        if(iOpcion == __FC_FD)       vFnMenuFd();
        if(iOpcion == __FC_SUMAFPU)  vFnMenuSumaFpu(pstuPCB[iFnBuscaPosicionProc(ulProcActual)].uiDirBase+iPar1, pstuPCB[iFnBuscaPosicionProc(ulProcActual)].uiDirBase+iPar2);
        if(iOpcion == __FC_VER)      vFnMenuVer();
        if(iOpcion == __FC_WINM)     {vFnCambiarVisibilidadVentanaProceso(); vFnImprimirContexto();}

	if(iOpcion == __FC_INTER)	{vFnImprimir("\nparece ser el intervalo");
					int lAux=lFnSysSchedRrGetInterval( 0,0);
					vFnImprimir("\nTime slice: %d",lAux);}
	if(iOpcion == __FC_CAMB)	vFnMenuCambiaTeclado(iPar1);
	if(iOpcion == __FC_LOGFC)	vFnTermLog(iPar1);
	if(iOpcion == __FC_LISTPART)	vFnMostrarListaParticiones();
	if(iOpcion == __FC_LISTPORC)	vFnMostrarTamaniosParticion();
        if(iOpcion == __FC_BORRARPF)    vFnBorrarUltimaPartFija();
        if(iOpcion == __FC_AGREGARPF)   vFnAgregarPartFija(pstuPCB[iFnBuscaPosicionProc(ulProcActual)].uiDirBase+iPar1);
        if(iOpcion == __FC_LISTAESP)    vFnRecorrerListaEspera();
        if(iOpcion == __FC_RESETPF)     vFnResetearListaPart();
	if(iOpcion == __FC_SETHEAPSIZE)     uiTamHeap = iPar1;

	// Sodium2010
    if(iOpcion == __FC_LOGSODUIM) return iFnVerLogSodium(iPar1,iPar2);
    if(iOpcion == __FC_VERHEADERELF) vFnVerHeaderELF(iPar1);

	return 0;
}


/**
 * @brief Syscall. Le pasa al proceso la lista de porcentajes para particion fija proporcional.
 * @param ptrPorcentaje. Offset desde el comienzo del proceso a la estructura de porcentajes.
 * @date 20/11/2009
 */
int lFnSysPorcentaje(int ptrPorcentaje)
{
        int i;

        for(i = 0; i < 100; i++) ((t_Porcentaje*)(pstuPCB[ulProcActual].uiDirBase+ptrPorcentaje))->piPorcentajesPartFija[i] = piPorcentajesPartFija[i];
	return 0;
}



/**
 * @brief Syscall (Sergio Martin 2009). Permite a un proceso redimensionar su tamaño para tener mas espacio de heap.
 * @param ulTamanioAdicional. Tamaño adicional solicitado
 * @date 20/11/2009
 */
long lFnSysSBrk(unsigned long ulTamanioAdicional) {

   if(iModo == FIJO) return -1;
   long int liTam;
   liTam = pstuPCB[ulProcActual].uiTamProc;
   vFnLog("\nSBRK. Pid: %d. Tam Actual: 0x%x. Incremento Deseado: 0x%x",ulProcActual,liTam, liTam + ulTamanioAdicional);
   return iFnRedimensionarProceso(ulProcActual,liTam + ulTamanioAdicional);


}

/**
 * @brief Syscall. Permite a un proceso redimensionar su tamaño para tener mas espacio de heap.
 * @param ulTamanioAdicional. Tamaño nuevo solicitado.
 * @date 20/11/2009
 */
long lFnSysBrk(unsigned long ulTamanioNuevo) {

   if(iModo == FIJO) return -1;
   long int liTam;
   liTam = pstuPCB[ulProcActual].uiTamProc;
   vFnLog("\nBRK. Pid: %d. Tam Actual: 0x%x. Tam Deseado: 0x%x",ulProcActual,liTam, liTam + ulTamanioNuevo);
   return iFnRedimensionarProceso(ulProcActual,ulTamanioNuevo);


}


// ****************     TP 3 - 2007 - Syscalls de IPC    *****************

/******************************************************************************
Funcion:
Descripcion:
Recibe:
Devuelve:
*******************************************************************************/
//long lFnSysSemInit( sem_t *sem, int pshared, unsigned int value ){
long lFnSysSemInit( sem_t *sem, sem_init_params * params ){
	params = (sem_init_params *)(pstuPCB[ ulProcActual ].uiDirBase + (unsigned int)params);

	return iFnSemInit(sem, params->pshared, params->value);
}
/******************************************************************************
Funcion:
Descripcion:
Recibe:
Devuelve:
*******************************************************************************/
long lFnSysSemPost( sem_t *sem ){
	return iFnSemPost(sem);
}
/******************************************************************************
Funcion:
Descripcion:
Recibe:
Devuelve:
*******************************************************************************/
long lFnSysSemWait( sem_t *sem ){
	return iFnSemWait(sem);
}
/******************************************************************************
Funcion:
Descripcion:
Recibe:
Devuelve:
*******************************************************************************/
long lFnSysSemClose( sem_t *sem ){
	return iFnSemClose(sem);
}
/******************************************************************************
Funcion:
Descripcion:
Recibe:
Devuelve:
*******************************************************************************/
long lFnSysShmGet(key_t key, size_t size){
	return iFnShmGet(key, size);
}
/******************************************************************************
Funcion:
Descripcion:
Recibe:
Devuelve:
*******************************************************************************/
long lFnSysShmAt( int shmid, void * shmAddr ){
	return iFnShmAt(shmid, shmAddr);
}
/******************************************************************************
Funcion:
Descripcion:
Recibe:
Devuelve:
*******************************************************************************/
long lFnSysShmDt( key_t key ){
	return iFnShmDt( key );
}


// ****************     TP 3 - 2007 - Syscalls de CLONE    *****************

/******************************************************************************
Funcion:
Descripcion:
Recibe:
Devuelve:
*******************************************************************************/
int iFnSysSumar(int a, int b,int * res)
{

	_copiar_a_userland( stuTSSTablaTareas[ ulProcActual ].ds,res,a+b);

	return *res;
}

/*Función: lFnSysNice
 * Parámetros:
 *	iIncremento (int): valor que quiero sumar a la prioridad del proceso
 *	actual.
 *Valor de retorno: 0
 *
 * Permite incrementar la prioridad del proceso actual en un valor pasado como
 * parámetro.
 */

long lFnSysNice(int iIncremento)
{
	long lNuevaPrio;


	lNuevaPrio = pstuPCB[ulProcActual].iPrioridad + iIncremento;

	if(lNuevaPrio < -20)
		lNuevaPrio = -20;

	if(lNuevaPrio > 19)
		lNuevaPrio = 19;


	pstuPCB[ulProcActual].iPrioridad  = lNuevaPrio;

	return 0;

}

/*Función: lFnSysGetpriority
 *Parámetros:
 *	which (int): indica cual es la prioridad que deseo conocer.
 *	Las opciones son: PRIO_PROCESS, PRIO_PGRP y PRIO_USER (las dos últimas
 *	no están implementadas todavía).
 *	who (int) : id del proceso.
 *Valor de retorno: devuelve un entero largo. Para evitar devolver un número
 *negativo, se retornan valores en un rango de 40 .. 1, en lugar de -20..19.
 *Esto se logra al restarle a 20 la prioridad del proceso.
 */

long lFnSysGetpriority(int which,int who)
{
	int iCont = 0;
	int iPrio;

	if(which > 2 || which < 0)
		return -EINVAL;

	if(which == PRIO_PROCESS)
	{
		if(who == 0)
		{
			iPrio = 20 - pstuPCB[ulProcActual].iPrioridad;
			return iPrio;
		}
		else
		{	/*busca el id en el vector de procesos*/
			for(iCont = 0; iCont < CANTMAXPROCS;iCont++)
			{
			        /*chequea que who sea un indice valido*/
				if(pstuPCB[iCont].ulId == who &&
				pstuPCB[iCont].iEstado != PROC_NO_DEFINIDO &&
				pstuPCB[iCont].iEstado != PROC_ELIMINADO)
				{
				iPrio = 20 - pstuPCB[iCont].iPrioridad;

				return iPrio;
				}
			}
		}
	}
	else
	{
	vFnImprimir("Prioridad de grupos y de usuarios en desarrollo\n");
	}

	/*No se encontró ningún proceso con el id pasado en who*/
	return -ESRCH;
}
/******************************************************************************
Funcion:
Descripcion:
Recibe:
Devuelve:
*******************************************************************************/
long lFnSysSetpriority(int which,int who,int iPrioridad)
{
	int iCont;

	if(which > 2 || which < 0)
		return -EINVAL;

	if(iPrioridad < -20)
		iPrioridad = -20;
	if(iPrioridad > 19)
		iPrioridad = 19;

	if(which == PRIO_PROCESS)
	{
		if(who == 0)
		{
		pstuPCB[ulProcActual].iPrioridad = iPrioridad;
		return 0;
		}
		else
		{
			for(iCont = 0; iCont < CANTMAXPROCS;iCont++)
			{
			        /*chequea que who sea un indice valido*/
				if(pstuPCB[iCont].ulId == who &&
				pstuPCB[iCont].iEstado != PROC_NO_DEFINIDO &&
				pstuPCB[iCont].iEstado != PROC_ELIMINADO)
				{
				 pstuPCB[iCont].iPrioridad = iPrioridad;

				return 0;
				}
			}
		}
	}
	else
	{
	vFnImprimir("Prioridad de grupos y de usuarios en desarrollo\n");
	}

	return -ESRCH;
}
/******************************************************************************
Funcion:lFnSysClone
Descripcion: Todavia no implementada.
Recibe:
Devuelve:
*******************************************************************************/
long lFnSysClone(stuRegs * regs,int flags)
{
	return -1;
}

// ****************     TP 3 - 2007 - Syscalls de tiempo    *****************
//Funciones
/******************************************************************************
Funcion:
Descripcion:
Recibe:
Devuelve:
*******************************************************************************/
unsigned uiFnPasarBCD(int iValor){
	unsigned iValorAlto, iValorBajo;
	iValorAlto = iValor /10;
	iValorBajo = iValor - (iValorAlto * 10);
	iValorAlto <<= 4;
	return (iValorAlto |= iValorBajo);
}
/******************************************************************************
Funcion:
Descripcion:
Recibe:
Devuelve:
*******************************************************************************/
long lFnSysSettime(timeval tp){
	// Contiene la info de a?o-mes-dia-hora-minuto-segundo (en ese orden)
	int iFecha[6];
	int iAnioActual = ANIO_INICIO;
	int iCantidadDiasAnio = DIAS_ANIO_INICIO;

	// Vectores que indican la secuencia de dias transcurridos asociados a los
	// meses que pertenecen dependiendo de si el a?o es bisiesto o no
	int iSecuenciaAnioBisiesto[13] = {0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366};
	int iSecuenciaAnioNoBisiesto[13] = {0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365};
	int i;

	// A partir de los segundos recibidos como parametro
	// obtenemos la cantidad de dias transcurridos
	long liTiempo = tp.tv_sec;
	int iCantidadDiasTranscurridos = liTiempo/86400;

	// Mantenemos la cantidad de segundos sobrantes
	liTiempo -= iCantidadDiasTranscurridos*86400;

	// Seteamos el a?o
	while(iCantidadDiasTranscurridos >= iCantidadDiasAnio)
	{
		iCantidadDiasTranscurridos -= iCantidadDiasAnio;

		iAnioActual ++;
		if (((iAnioActual % 4 == 0) && ((iAnioActual % 100 != 0) || (iAnioActual % 400 == 0))) == 1)
			iCantidadDiasAnio = 366;
		else
			iCantidadDiasAnio = 365;
	}

	// Seteamos el mes y el dia
	if (((iAnioActual % 4 == 0) && ((iAnioActual % 100 != 0) || (iAnioActual % 400 == 0))) == 1){
		for(i = 0; iCantidadDiasTranscurridos >= iSecuenciaAnioBisiesto[i]; i++);
	}

	else{
		for(i = 0; iCantidadDiasTranscurridos >= iSecuenciaAnioNoBisiesto[i]; i++);
	}

	if (((iAnioActual % 4 == 0) && ((iAnioActual % 100 != 0) || (iAnioActual %400 == 0))) == 1)	{
		iCantidadDiasTranscurridos -= iSecuenciaAnioBisiesto[i-1];
	}

	else{
		iCantidadDiasTranscurridos -= iSecuenciaAnioNoBisiesto[i-1];
	}

   // Almacenamos el a?o en el vector temporal
   // Del a?o solo nos interesan los ?ltimos 2 digitos (asi lo solicita el CMOS)
   // Analizar problema producido para fechas mayores al 2099.
	iFecha[0] = iAnioActual - ANIO_INICIO;

   // Almacenamos dia y mes en el vector temporal
	iFecha[1] = i;
	iFecha[2] = iCantidadDiasTranscurridos + 1;

	// Almacenamos la hora
	iFecha[3] = liTiempo / 3600;
	liTiempo -= iFecha[3] * 3600;

	// Almacenamos los minutos
	iFecha[4] = liTiempo / 60;
	liTiempo-=iFecha[4] * 60;

	// Almacenamos los segundos
	iFecha[5] = liTiempo;

	outb(9, 0x70);
	outb(uiFnPasarBCD(iFecha[0]), 0x71);
	outb(8, 0x70);
	outb(uiFnPasarBCD(iFecha[1]), 0x71);
	outb(7, 0x70);
	outb(uiFnPasarBCD(iFecha[2]), 0x71);
	outb(4, 0x70);
	outb(uiFnPasarBCD(iFecha[3]), 0x71);
	outb(2, 0x70);
	outb(uiFnPasarBCD(iFecha[4]), 0x71);
	outb(0, 0x70);
	outb(uiFnPasarBCD(iFecha[5]), 0x71);

	// Seteamos la variable  ulTiempo que contiene la hora actual del sistema
	ulTiempo = tp.tv_sec * 1000 + tp.tv_usec;

	return 0;
}
/******************************************************************************
Funcion:
Descripcion:
Recibe:
Devuelve:
*******************************************************************************/
long lFnSysStime(time_t *newtime){

	timeval timervalTime;
	long lRetorno;

	time_t *tiempo = (time_t *)(pstuPCB[ ulProcActual ].uiDirBase + (unsigned int)newtime);
	timervalTime.tv_sec = *tiempo;
	timervalTime.tv_usec = 0;

	lRetorno = lFnSysSettime(timervalTime);
	return lRetorno;
}
/******************************************************************************
Funcion:
Descripcion:
Recibe:
Devuelve:
*******************************************************************************/
long lFnSysTimes(tms *tmsBuffer){
	tms *tmsTiempos = (tms *)(pstuPCB[ ulProcActual ].uiDirBase + (unsigned int)tmsBuffer);
	tms tmsTiemposReales = pstuPCB[ ulProcActual ].stuTmsTiemposProceso;
	tmsTiempos->tms_utime = tmsTiemposReales.tms_utime / 2;
	tmsTiempos->tms_stime = tmsTiemposReales.tms_stime / 2;
	tmsTiempos->tms_cutime = tmsTiemposReales.tms_cutime / 2;
	tmsTiempos->tms_cstime = tmsTiemposReales.tms_cstime / 2;
	return uliClockTick;
}
/******************************************************************************
Funcion:
Descripcion:
Recibe:
Devuelve:
*******************************************************************************/
long lFnSysGettimeofday(timeval *timervalTp, timezone *timezoneTzp){
	timeval *timevalTime = (timeval *)(pstuPCB[ ulProcActual ].uiDirBase + (unsigned int)timervalTp);
	timezone *timezoneZona = (timezone *)(pstuPCB[ ulProcActual ].uiDirBase + (unsigned int)timezoneTzp);

	unsigned long ulMilisegundos = ulTiempo;
	timevalTime->tv_sec = ulMilisegundos/1000;
	timevalTime->tv_usec = ulMilisegundos - (timevalTime->tv_sec*1000);
	timevalTime->tv_sec += (iMinuteswest*60);
	timezoneZona->tz_minuteswest = iMinuteswest;
	timezoneZona->tz_dsttime = 0;
	return 0;
}
/******************************************************************************
Funcion:
Descripcion:
Recibe:
Devuelve:
*******************************************************************************/

long lFnSysGettimer(int iWhich, itimerval *itimervalValue){
	itimerval *itimervalTimer;

	if (iWhich != ITIMER_REAL && iWhich != ITIMER_VIRT && iWhich != ITIMER_PROF)
		return -EINVAL;

	itimervalTimer = (itimerval *)(pstuPCB[ ulProcActual ].uiDirBase + (unsigned int) itimervalValue);
	itimervalTimer->it_interval = pstuPCB[ ulProcActual ].timers[iWhich].it_interval;
	itimervalTimer->it_value = pstuPCB[ ulProcActual ].timers[iWhich].it_value;
	return 0;
}
/******************************************************************************
Funcion:
Descripcion:
Recibe:
Devuelve:
*******************************************************************************/
long lFnSysSettimeofday(timeval *timevalTp, timezone *timezoneTzp){
	timeval timevalTime = *(timeval *)(pstuPCB[ ulProcActual ].uiDirBase + (unsigned int)timevalTp);
	timezone timezoneZona = *(timezone *)(pstuPCB[ ulProcActual ].uiDirBase + (unsigned int)timezoneTzp);

	iMinuteswest = timezoneZona.tz_minuteswest;
	return lFnSysSettime(timevalTime);
}
/******************************************************************************
Funcion:
Descripcion:
Recibe:
Devuelve:
*******************************************************************************/
long lFnSysSettimer(int which, itimerval const *value, itimerval *ovalue){
	itimerval *timerViejo;
	itimerval *timer;
	if (which != ITIMER_REAL && which != ITIMER_VIRT && which != ITIMER_PROF){
		return -EINVAL;
	}

	timerViejo = (itimerval *)(pstuPCB[ ulProcActual ].uiDirBase + (unsigned int) ovalue);
	timer = (itimerval *)(pstuPCB[ ulProcActual ].uiDirBase + (unsigned int) value);
	timerViejo->it_interval = pstuPCB[ ulProcActual ].timers[which].it_interval;
	timerViejo->it_value = pstuPCB[ ulProcActual ].timers[which].it_value;
	pstuPCB[ ulProcActual ].timers[which].it_value = timer->it_value;
	pstuPCB[ ulProcActual ].timers[which].it_interval = timer->it_interval;
	return 0;
}
/******************************************************************************
Funcion:
Descripcion:
Recibe:
Devuelve:
*******************************************************************************/
long lFnSysAdjtimex(timex *timexBuffer){
	timex *timexTimeVars;
	int modo, iNewFreq;

	timexTimeVars = (timex *)(pstuPCB[ ulProcActual ].uiDirBase + (unsigned int) timexBuffer);
	modo = timexTimeVars->modes;

	if (modo){
		if (modo & ADJ_STATUS){
			return -EINVAL;
			//iRelojEstado = timexTimeVars->status;
		}
		if (modo & ADJ_FREQUENCY){
			return -EINVAL;
			//lRelojFrequencia = timexTimeVars->freq;
		}
		if (modo & ADJ_MAXERROR){
			return -EINVAL;
			//lRelojMaxerror = timexTimeVars->maxerror;
		}
		if (modo & ADJ_ESTERROR){
			return -EINVAL;
			//lRelojEsterror = timexTimeVars->esterror;
		}
		if (modo & ADJ_TIMECONST){
			return -EINVAL;
			//lRelojConstante = timexTimeVars->constant;
		}
		if (modo & ADJ_OFFSET){
			return -EINVAL;
			/*if (modo & ADJ_OFFSET_SINGLESHOT){
			}*/
		}
		if (modo & ADJ_TICK){
			if (timexTimeVars->tick < 1)
				return -EINVAL;
			iNewFreq = (timexTimeVars->tick * TIMER_FREQ_REAL) / 1000;
			vFnImprimir("\nDivisor = %d", iNewFreq);
			vFnIniciarTimer_Asm(iNewFreq);
			iMilisegundosPorTick = timexTimeVars->tick;
			lRelojMaxerror = (((1000000 * iNewFreq) / TIMER_FREQ_REAL) - (iMilisegundosPorTick * 1000) * TIMER_TICKS_UPDATE_DEFAULT) / 1000;
		}
	}

	timexTimeVars->offset = lRelojOffset;
	timexTimeVars->freq = lRelojFrequencia;
	timexTimeVars->maxerror = lRelojMaxerror;
	timexTimeVars->esterror = lRelojEsterror;
	timexTimeVars->constant = lRelojConstante;
	timexTimeVars->precision = PRECISION_RELOJ;
	timexTimeVars->time.tv_sec = ulTiempo / 1000;
	timexTimeVars->time.tv_usec = ulTiempo - (timexTimeVars->time.tv_sec * 1000);
	timexTimeVars->tick = iMilisegundosPorTick;

	return iRelojEstado;
}
/******************************************************************************
Funcion:
Descripcion:
Recibe:
Devuelve:
*******************************************************************************/
long lFnSysNanosleep(timespec const *timespecRequested_time, timespec *timespecRemaining){
	timespec timespecTiempoRequerido;

	timespecTiempoRequerido = *(timespec *)(pstuPCB[ ulProcActual ].uiDirBase + (unsigned int) timespecRequested_time);

	if (timespecTiempoRequerido.tv_sec < 0 || timespecTiempoRequerido.tv_nsec < 0 || timespecTiempoRequerido.tv_nsec > 999999999)
		return -EINVAL;
	pstuPCB[ ulProcActual ].iEstado = PROC_DETENIDO;
	timespecTiempoRequerido.tv_nsec/= 1000000;
	pstuPCB[ ulProcActual ].lNanosleep = (timespecTiempoRequerido.tv_sec * 1000) + timespecTiempoRequerido.tv_nsec;
	pstuPCB[ ulProcActual ].puRestoDelNanosleep = timespecRemaining;
	vFnPlanificador();
	return 0;
}

/*SysCall Planificacion Sodix*/
/******************************************************************************
Funcion:
Descripcion:
Recibe:
Devuelve:
*******************************************************************************/
long lFnSysIdle()
{
  unsigned int uiVectorDescriptorAuxiliarTarea[2];

  vFnImprimirOk(55);
  /*vFnImprimirContextSwitch (ROJO, pstuPCB[iTareaNula].ulId,
					pstuPCB[iTareaNula].stNombre,
					pstuPCB[iTareaNula].uiIndiceGDT_TSS);*/

  if (pstuPCB[staiN].iEstado != PROC_ELIMINADO
		  && pstuPCB[staiN].iEstado != PROC_ZOMBIE
		  && pstuPCB[staiN].iEstado != PROC_ESPERANDO
		  && pstuPCB[staiN].iEstado != PROC_DETENIDO)
		pstuPCB[staiN].iEstado = PROC_LISTO;	//paso el proceso que estaba en ejecuci?n a listo

		  pstuPCB[iTareaNula].iEstado = PROC_EJECUTANDO;	//paso al actual de listo a running

  		  staiProcesoAnterior = staiN;
	      ulProcActual = iTareaNula;

	      /* uiVectorDescriptorAuxiliarTarea[0] = offset. Este par?metro no hace falta
	         cargarlo porque es ingnorado al momento del salto a
	         un descriptor, lo ?nico que interesa el el selector
	         en s? mismo */

	      uiVectorDescriptorAuxiliarTarea[1] = pstuPCB[iTareaNula].uiIndiceGDT_TSS * 8;	/* multiplicamos el indice por
											   8 para tener el offset en bytes
											   desde el inicio de la gdt hasta
											   el selector que nos interesa */

	    asm ("clts\t\n" "ljmp *%0": :"m" (*uiVectorDescriptorAuxiliarTarea));

	return 0;
}
/******************************************************************************
Funcion:
Descripcion:
Recibe:
Devuelve:
*******************************************************************************/
long lFnSysSchedSetParam(int p)
{
    if(lFnSysSchedGetScheduler()==FIFO){
	}
	if(lFnSysSchedGetScheduler()==BTS){
		uliBTSQ = p;
	}
	if(lFnSysSchedGetScheduler()==RR){
		uliQuantum = p;
	}

	return lFnSysSchedSetScheduler(p);
}
/******************************************************************************
Funcion:
Descripcion:
Recibe:
Devuelve:
*******************************************************************************/
long lFnSysSchedSetScheduler(int p)
{
    if(p==FIFO)//0
    {
    	bPlanificador=FIFO;
       return FIFO;
    }
    if(p==RR)//1
    {
       uliQuantum=QUANTUM;
	   bPlanificador=RR;
       return RR;
    }
    if(p==BTS)//1
    {
       uliQuantum=QBTS;
       bPlanificador=BTS;
       return BTS;
    }
    return -1;
}
/******************************************************************************
Funcion:
Descripcion:
Recibe:
Devuelve:
*******************************************************************************/
long lFnSysSchedGetParam()
{
    if(bPlanificador==RR){
       return uliQuantum;
    }
    if(bPlanificador==FIFO){
       return -1;
    }
	if(bPlanificador==BTS){
	   return uliBTSQ;
	}

	return -1;
}

/******************************************************************************
Funcion:
Descripcion:
Recibe:
Devuelve:
*******************************************************************************/
long lFnSysSchedGetScheduler()
{
	return bPlanificador;
}
/******************************************************************************
Funcion:
Descripcion:
Recibe:
Devuelve:
*******************************************************************************/
long lFnSysSchedYield()
{
	//llamamos al planificador y ya,
	//esto saca al proceso de ejecucion y pone al siguiente
	vFnPlanificador();
	return 0;
}
/******************************************************************************
Funcion:
Descripcion:
Recibe:
Devuelve:
*******************************************************************************/
long lFnSysSchedGetPriorityMax()
{
    if(bPlanificador==BTS){
		return 1; //calcular la prioridad para BTS, sin no es, devolver -1
	}
	return -1;
}
/******************************************************************************
Funcion:
Descripcion:
Recibe:
Devuelve:
*******************************************************************************/
long lFnSysSchedGetPriorityMin()
{
    if(bPlanificador==BTS){
		return CANTMAXPROCS; //calcular la prioridad para BTS, sin no es, devolver -1
	}
	return -1;
}
/******************************************************************************
Funcion:
Descripcion:
Recibe:
Devuelve:
*******************************************************************************/
long lFnSysSchedRrGetInterval()
{
    return uliTimeSlice;
}

/***************************************************************************
Funcion:
Descripcion:
Recibe:
Devuelve:
*******************************************************************************/
long lFnSysPtrace( int iRequest, void *pvDirParam ) {

	__ptrace_param *pstuParam;

	//void*   pvTssParam;
	stuRegs* pstuTss;
	//estructura con los registros del FPU
	stuFpu* pstuFpu;

	/* Necesario para acceder a las variables de un proceso particular (indireccion) */
	pvDirParam = (void *)(pstuPCB[ ulProcActual ].uiDirBase + (unsigned int)pvDirParam );
	pstuParam = (__ptrace_param *)pvDirParam;

	if ( iFnBuscaPosicionProc(pstuParam->iPid) < 0 || pstuPCB[ iFnBuscaPosicionProc(pstuParam->iPid) ].iEstado == PROC_ZOMBIE ){
		return -ESRCH;
	}

	/* Valido que el pedido a ejecutar tenga los permisos adecuados */
	if ( (iRequest != PTRACE_ATTACH) && (iRequest != PTRACE_TRACEME) ) // 13 y 0 respectivamente
	{
		if ( (pstuPCB[iFnBuscaPosicionProc(pstuParam->iPid)].lPidTracer == PROC_WOTRACER) || (pstuPCB[iFnBuscaPosicionProc(pstuParam->iPid)].lPidTracer != pstuPCB[ulProcActual].ulId) )
		{
			return -EPERM;
		}
	}

	switch ( iRequest ) {
		case( PTRACE_TRACEME ):
			/* Relaciono el Hijo con el Padre usando solo el paràmetro REQUEST */
			if (pstuPCB[ ulProcActual ].lPidTracer == PROC_WOTRACER)
				pstuPCB[ulProcActual].lPidTracer = pstuPCB[ulProcActual].ulParentId;
			else
				return -EPERM;
			break;
		case( PTRACE_PEEKTEXT ):
			pstuParam->pvData = (void*)(*(int*)( pstuPCB[ iFnBuscaPosicionProc(pstuParam->iPid) ].uiDirBase + (unsigned)pstuParam->pvAddr) );
			break;
		case( PTRACE_PEEKDATA ):
			pstuParam->pvData = (void*)(*(int*)( pstuPCB[ iFnBuscaPosicionProc(pstuParam->iPid) ].uiDirBase + (unsigned)pstuParam->pvAddr) );
			break;
		case( PTRACE_PEEKUSER ):
			pstuParam->pvData = (void*)(*(int*)( pstuPCB[ iFnBuscaPosicionProc(pstuParam->iPid) ].uiDirBase + (unsigned)pstuParam->pvAddr) );
			break;
		case( PTRACE_POKETEXT ):
			*(int*)( pstuPCB[ iFnBuscaPosicionProc(pstuParam->iPid) ].uiDirBase + (unsigned)pstuParam->pvAddr ) = (int)pstuParam->pvData;
			break;
		case( PTRACE_POKEDATA ):
			*(int*)( pstuPCB[ iFnBuscaPosicionProc(pstuParam->iPid) ].uiDirBase + (unsigned)pstuParam->pvAddr ) = (int)pstuParam->pvData;
			break;
		case( PTRACE_POKEUSER ):
			*(int*)( pstuPCB[ iFnBuscaPosicionProc(pstuParam->iPid) ].uiDirBase + (unsigned)pstuParam->pvAddr ) = (int)pstuParam->pvData;
			break;
		case( PTRACE_GETREGS ):
			pstuTss = (stuRegs*)(pstuPCB[ ulProcActual ].uiDirBase + (unsigned int)pstuParam->pvData );
			pstuTss->eax = stuTSSTablaTareas[ iFnBuscaPosicionProc(pstuParam->iPid) ].eax;
			pstuTss->ebx = stuTSSTablaTareas[ iFnBuscaPosicionProc(pstuParam->iPid) ].ebx;
			pstuTss->ecx = stuTSSTablaTareas[ iFnBuscaPosicionProc(pstuParam->iPid) ].ecx;
			pstuTss->edx = stuTSSTablaTareas[ iFnBuscaPosicionProc(pstuParam->iPid) ].edx;
			break;
		case( PTRACE_GETFPREGS ):
			/* Con este iRequest deberìamos pasar a la API los valores de los registros de punto flotante
			** que obtenidos del Copro, pero como Sodium actualmente no maneja punto flotante
			** no los podemos obtener, quedan pendientes para la pròxima revisiòn.
			*/
			pstuFpu = (stuFpu*)(pstuPCB[ ulProcActual ].uiDirBase + (unsigned int)pstuParam->pvData );
			/* Si el ultimo proceso en usar la FPU es el proceso a "tracear",
			 * su TSS estara desactualizada
			 * y los valores habra que sacarlos directamente el FPU
			 */
			if( ulUltimoProcesoEnFPU == pstuParam->iPid ) {
			  //Se guarda el estado actual de la FPU, en la TSS del proceso hijo
			  asm volatile(
					  "fnsave %0\n"
					  "fwait	\n"
					  "frstor %0\n"
					  : "=m" (*pstuFpu));
			} else {
				//La TSS del proceso a "tracear" esta actualizada
				//asi que tomamos los valores de la misma
				ucpFnCopiarMemoria( (unsigned char*) pstuFpu,
									(unsigned char*) &stuTSSTablaTareas[iFnBuscaPosicionProc(pstuParam->iPid)].fpu,
									sizeof(stuFpu));
			}
			break;
		case( PTRACE_SETREGS ):
			pstuTss = (stuRegs*)(pstuPCB[ ulProcActual ].uiDirBase + (unsigned int)pstuParam->pvData );
			stuTSSTablaTareas[ iFnBuscaPosicionProc(pstuParam->iPid) ].eax = pstuTss->eax;
			stuTSSTablaTareas[ iFnBuscaPosicionProc(pstuParam->iPid) ].ebx = pstuTss->ebx;
			stuTSSTablaTareas[ iFnBuscaPosicionProc(pstuParam->iPid) ].ecx = pstuTss->ecx;
			stuTSSTablaTareas[ iFnBuscaPosicionProc(pstuParam->iPid) ].edx = pstuTss->edx;
			break;
		case( PTRACE_SETFPREGS ):
			/* En este iRequest deberìamos setear los valores de los registros de punto flotante
			** que recibimos en pvDirParam, pero como Sodium actualmente no maneja punto flotante
			** no los podemos setear, quedan pendientes para la pròxima revisiòn.
			*/
			pstuFpu = (stuFpu*)(pstuPCB[ ulProcActual ].uiDirBase + (unsigned int)pstuParam->pvData );

			//La TSS del proceso a "tracear" se sobreescribe con los valores recibidos
			ucpFnCopiarMemoria( (unsigned char*) &stuTSSTablaTareas[iFnBuscaPosicionProc(pstuParam->iPid)].fpu,
								(unsigned char*) pstuFpu,
								sizeof(stuFpu));

			/* Si el ultimo proceso en utilizar el FPU fue el proc. a "tracear", 			 * se fuerza a que la proxima vez que se use el FPU se tomen
			 * los datos de la TSS recien actualizada
			 */
			if( ulUltimoProcesoEnFPU == pstuParam->iPid ) {
				ulUltimoProcesoEnFPU = 0;
			}

			break;
		case( PTRACE_CONT ):
			return lFnSysKill( pstuParam->iPid, SIGCONT);
			break;
		case( PTRACE_KILL ):
			return lFnSysKill( pstuParam->iPid, SIGKILL);
			break;
		case( PTRACE_ATTACH ):
			if ( pstuPCB[ iFnBuscaPosicionProc( pstuParam->iPid ) ].lPidTracer == PROC_WOTRACER )
 				pstuPCB[iFnBuscaPosicionProc(pstuParam->iPid)].lPidTracer = pstuPCB[ulProcActual].ulId;
			else
				return -EPERM;
			break;
		case( PTRACE_DETACH ):
			/* Desvinculo al Hijo del proceso que lo rastrea */
			pstuPCB[iFnBuscaPosicionProc(pstuParam->iPid)].lPidTracer = PROC_WOTRACER;
			break;
		default:
			return -EINVAL;
	}

	return 0l;
}


/******************************************************************************
Funcion: void vFnEsperarPID(int iArgumento)
Descripcion: Espera la culminacion de un proceso cuyo PID se le pasa como parametro.
Recibe: PID del PID
Devuelve: Nada.
*******************************************************************************/
void vFnEsperarPID(int iArgumento)
{
int ret = 0, status = 0, pid = 0;

if (iArgumento >= 0)
	{
	ret = lFnSysWaitPid(iArgumento, &status, 0);
	vFnImprimir("\nel syscall waitpid() me devolvio %d, y estado quedo en %d", ret, status);
	}
else
	vFnImprimir("\nPID invalido.");
}


/******************************************************************************
Sodium2010
Funcion: void vFnVerLogSodium(int iNivel)
Descripcion: Mostrar los eventos logueados
Recibe: Nivel por lo cual se quiere filtrar (0: Todo el log, 1: bootSector, 2: loader, 3: sodium, 4: main)
Devuelve: nada
*******************************************************************************/
int iFnVerLogSodium(int iNivel, int iPaso)
{
    int iN = 0;
    int iCont = 0;
	int iNumLog=0;
	// Logueo habilitado
    if (usHabilitarLogueo == LOGUEOHABILITADO)
    {
		// Parametro valido (0, 1, 2 ,3 4)
		if (iNivel >= 0 && iNivel <= 4)
		{
			for (iN = iPaso; iN < usCantidadLog; iN++)
			{
				if (iNivel == vstuLogueoDato[iN].iCogidoNivel || iNivel == 0)
				{
					if (iPaso != 0 && iNivel == 4)
					  iPaso = 11;

					iNumLog++;
					vFnImprimir("\n%d - %s",iNumLog+iPaso,vstuLogueoDato[iN].stLogDato);

					if(iPaso==0 && iCont==0)
						iCont=3;
					else
						iCont++;

					if(iCont==13)
						return iN;
				}
			}
			vFnImprimir("\nFin del proceso logsodium");
		}
		else
			vFnImprimir("\nEl parametro ingresado es incorrecto.");

	}
    else
      vFnImprimir("\nEl Log del Sodium esta deshabilitado.\n");

	vFnImprimir("\nPresione cualquier tecla para salir...");

  return 0;
}

/******************************************************************************
Sodium2010
Funcion: void vFnLogSodium(int iNivel, char * cMensaje)
Descripcion: Cargar vector de eventos para loguear
Recibe: El nivel de evento y el mensaje a mostrar
Devuelve: nada
*******************************************************************************/
void vFnLogSodium(int iNivel, char * cMensaje)
{
    if (usHabilitarLogueo == LOGUEOHABILITADO)
    {
      vstuLogueoDato[usCantidadLog].stLogDato = cMensaje;
      vstuLogueoDato[usCantidadLog].iCogidoNivel = iNivel;
      usCantidadLog++;
    }
}


/******************************************************************************
Sodium2010
Funcion: void vFnVerHeaderELF(int iPid)
Descripcion: Cargar vector de eventos para loguear
Recibe: El nivel de evento y el mensaje a mostrar
Devuelve: nada
*******************************************************************************/
void vFnVerHeaderELF(int iPid)
{
	int i=0;
	if(iFnBuscaPosicionProc(iPid) != -1)
	{	
	    vFnImprimir("\nCabecera ELF. PID: %d Proceso: %s", iPid, pstuPCB[iPid].stNombre);
	
		// obtener el PCB del proceso actual
		
		vFnImprimir("\nIdentificador: %c%c%c. \t", pstuPCB[iFnBuscaPosicionProc(iPid)].stuCabeceraELF.elfHeaderData.ident[1],pstuPCB[iFnBuscaPosicionProc(iPid)].stuCabeceraELF.elfHeaderData.ident[2],pstuPCB[iFnBuscaPosicionProc(iPid)].stuCabeceraELF.elfHeaderData.ident[3]);
		vFnImprimir("Tipo de archivo: %s.", cFnTextoHeaderELF(1, pstuPCB[iFnBuscaPosicionProc(iPid)].stuCabeceraELF.elfHeaderData.type));
		vFnImprimir("\nTipo de arquitectura: %s. \t", cFnTextoHeaderELF(2, pstuPCB[iFnBuscaPosicionProc(iPid)].stuCabeceraELF.elfHeaderData.machine));
		vFnImprimir("Version: %d.", pstuPCB[iFnBuscaPosicionProc(iPid)].stuCabeceraELF.elfHeaderData.version);
		vFnImprimir("\nPunto de entrada: %d. \t", pstuPCB[iFnBuscaPosicionProc(iPid)].stuCabeceraELF.elfHeaderData.entry);
		vFnImprimir("Offset Program Header Table: %d bytes.", pstuPCB[iFnBuscaPosicionProc(iPid)].stuCabeceraELF.elfHeaderData.phoff);
		vFnImprimir("\nOffset Section Header Table: %d bytes. \t", pstuPCB[iFnBuscaPosicionProc(iPid)].stuCabeceraELF.elfHeaderData.sphoff);
		vFnImprimir("Flags: %d.", pstuPCB[iFnBuscaPosicionProc(iPid)].stuCabeceraELF.elfHeaderData.flags);
		vFnImprimir("\nTamanio cabecera ELF: %d bytes. \t", pstuPCB[iFnBuscaPosicionProc(iPid)].stuCabeceraELF.elfHeaderData.ehsize);
		vFnImprimir("\nTamanio entrada Program Header Table: %d bytes.", pstuPCB[iFnBuscaPosicionProc(iPid)].stuCabeceraELF.elfHeaderData.phentsize);
		vFnImprimir("\nCantidad de entradas de Program Header Table: %d. \t", pstuPCB[iFnBuscaPosicionProc(iPid)].stuCabeceraELF.elfHeaderData.phnum);
		vFnImprimir("\nTamanio entrada Section Header Table: %d bytes.", pstuPCB[iFnBuscaPosicionProc(iPid)].stuCabeceraELF.elfHeaderData.shentsize);
		vFnImprimir("\nCantidad de entradas de Section Header Table: %d. \t", pstuPCB[iFnBuscaPosicionProc(iPid)].stuCabeceraELF.elfHeaderData.shnum);
		vFnImprimir("\nIndice de entrada Section Header Table: %d.", pstuPCB[iFnBuscaPosicionProc(iPid)].stuCabeceraELF.elfHeaderData.shstrndx);

		//	Tamaño en bytes de segmento de código.
		vFnImprimir("\nTamanio en bytes de segmento de codigo: %d.", pstuPCB[iFnBuscaPosicionProc(iPid)].stuCabeceraELF.PHeaderData[0].memsz);
		//	Tamaño en bytes de segmento de datos.   --> uiLimite
		vFnImprimir("\nTamanio en bytes de segmento de datos: %d.", pstuPCB[iFnBuscaPosicionProc(iPid)].uiLimite);
		//	Tamaño de pagina.   --> TAMANIOPAGINA
		vFnImprimir("\nTamanio de pagina: %d.", TAMANIOPAGINA);
		//	Tamaño de BSS.   --> pstuPCB[].stSHeaderData[4].size
		vFnImprimir("\nTamanio de BSS: %d.", pstuPCB[iFnBuscaPosicionProc(iPid)].stSHeaderData[4].size);

		//vFnVerTablaPaginas();
	}
	else
		vFnImprimir("\nEl proceso no existe");
}

/******************************************************************************
Sodium2010
Funcion: char * cFnTextoHeaderELF(short sOpcion, int iValor)
Descripcion: Devuelve el valor del Tipo y Machine de la cabecera ELF
Recibe: La opcion a evaluar (Tipo o Machine), y valor a obtener 
Devuelve: Texto con la descripcion
*******************************************************************************/
char * cFnTextoHeaderELF(short sOpcion, int iValor)
{
	switch(sOpcion)
	{
		case 1:  // type
			if (iValor == 0)
				return "Ningun tipo";
			else if (iValor == 1)
				return "Reubicable";
			else if (iValor == 2)
				return "Ejecutable";
			else if (iValor == 3)
				return "Objeto compartido";
			else if (iValor == 4)
				return "Core";
			else return "Desconocido";
			break;
		case 2: // machine
			if (iValor == 0)
				return "Ninguna maquina";
			else if (iValor == 2)
				return "SPARC";
			else if (iValor == 3)
				return "Intel 80386";
			else if (iValor == 18)
				return "Sun SPARC 32";
			else if (iValor == 43)
				return "SPARC V9";
			else if (iValor == 62)
				return "AMD 64";
			else return "Desconocido";
			break;
	}
	return "";
}


/******************************************************************************
Sodium2010
Funcion: void vFnVerTablaPaginas()
Descripcion: Muestra datos de la tabla de paginas y la memoria
Recibe: Pid del proceso
*******************************************************************************/
void vFnVerTablaPaginas()
{
	vFnImprimir("\n Tamanio Memoria: %d Bytes.\n", MEM_TOPE - MEM_BASE);
	vFnImprimir(" Numero de frames en memoria: %d\n", uiCantFrames);
	if (uiCantFrames != 0)
	{
		vFnImprimir(" Numero de frames ocupados: %d\n", (uiCantFrames - uiCantFramesLibres));
		vFnImprimir(" Numero de frames libres: %d\n",  uiCantFramesLibres);
	}
	else
	{
		vFnImprimir(" Numero de frames ocupados: %d\n", uiCantFrames);	
		vFnImprimir(" Numero de frames libres: %d\n",  uiCantFrames);
	}
}
